package com.qiaofang.applet.service.other.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.client.yxim.model.YxReceiveMsg;
import com.qiaofang.applet.common.context.QfContextHolder;
import com.qiaofang.applet.constants.BusinessConstants;
import com.qiaofang.applet.constants.UserType;
import com.qiaofang.applet.service.member.domain.Employee;
import com.qiaofang.applet.service.member.service.DepartmentService;
import com.qiaofang.applet.service.member.service.EmployeeService;
import com.qiaofang.applet.service.member.service.MemberService;
import com.qiaofang.applet.service.other.domain.Corporation;
import com.qiaofang.applet.service.other.domain.MessageList;
import com.qiaofang.applet.service.other.domain.MessageParam;
import com.qiaofang.applet.service.other.domain.YxImMessage;
import com.qiaofang.applet.service.other.repository.MessageListRepository;
import com.qiaofang.applet.service.other.repository.YxImMessageRepository;
import com.qiaofang.applet.service.other.service.CityCompanyService;
import com.qiaofang.applet.service.other.service.YxImMessageService;
import com.qiaofang.applet.service.other.service.YxImUserService;
import com.qiaofang.applet.service.other.service.dto.MessageListQueryDto;
import com.qiaofang.applet.service.property.domain.FirsthandEstate;
import com.qiaofang.applet.service.property.domain.Property;
import com.qiaofang.applet.service.property.service.FirsthandEstateService;
import com.qiaofang.applet.service.property.service.PropertyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 网易云信im
 *
 * @author junze.liu
 */
@Slf4j
@Service
public class YxImMessageServiceImpl extends MongoBaseService<YxImMessage, String> implements YxImMessageService {

    private final YxImMessageRepository repository;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CityCompanyService cityCompanyService;

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private FirsthandEstateService firsthandEstateService;

    @Autowired
    private PropertyService propertyService;

    @Autowired
    private YxImUserService yxImUserService;

    @Autowired
    private MessageListRepository messageListRepository;

    @Autowired
    private MemberService memberService;

    @Autowired
    private EmployeeService employeeService;

    @Autowired
    public YxImMessageServiceImpl(YxImMessageRepository repository) {
        super(repository);
        this.repository = repository;
    }

    @Override
    @Async
    public void saveByReceiveMsg(String receiveMsg) {
        YxReceiveMsg msg = JSONObject.parseObject(receiveMsg, YxReceiveMsg.class);
        //根据fromAccount获取集团code
        String corporationCode = getCorporationCodeByAccid(msg.getFromAccount());
        if (StringUtils.isEmpty(corporationCode)) {
            log.error("保存网易云信消息抄送失败，未获取到集团表信息");
            return;
        }
        //当消息类型不是自定义消息（房源消息）时，不保存
        if (!"CUSTOM".equals(msg.getMsgType())) {
            return;
        }
        JSONObject attachJson = JSONObject.parseObject(msg.getAttach());
        //获取自定义消息中的data数据
        String data = attachJson.getString("data");
        JSONObject dataJson = JSONObject.parseObject(data);
        //保存历史消息
        YxImMessage entity = new YxImMessage();
        entity.setCorporationCode(corporationCode);
        entity.setFromAccid(msg.getFromAccount());
        entity.setToAccid(msg.getTo());
        entity.setEventType(msg.getEventType());
        entity.setConvType(msg.getConvType());
        entity.setFromClientType(msg.getFromClientType());
        entity.setMsgType(msg.getMsgType());
        entity.setLastmsgtext(data);
        entity.setBusinessUniqueUuid(dataJson.getString("propertyId"));
        entity.setBusinessType(attachJson.getString("type"));
        entity.setMsgTimestamp(new Date(msg.getMsgTimestamp()));
        entity.setCronOpFlag(false);
        repository.insert(entity);
    }

    @Override
    public Page<MessageList> findMessageListByParam(MessageListQueryDto queryDto, Pageable pageable) {
        // 1、拼查询公共条件
        Query queryCriteria = createFindQuery(queryDto);

        // 2、拼分页参数
        queryCriteria.with(pageable);

        // 3、查询记录条件
        long count = mongoTemplate.count(queryCriteria, MessageList.class);
        List<MessageList> list = new ArrayList<>();
        if (count > 0) {
            // 4、分页查询数据
            list = mongoTemplate.find(queryCriteria, MessageList.class);
        }
        return PageableExecutionUtils.getPage(list, pageable, () -> count);
    }

    @Override
    public List<MessageList> findMessageListByParam(MessageListQueryDto queryDto) {
        // 1、拼查询公共条件
        Query queryCriteria = createFindQuery(queryDto);
        return mongoTemplate.find(queryCriteria, MessageList.class);
    }

    private Query createFindQuery(MessageListQueryDto queryDto) {
        Query query = new Query();

        Criteria criteria = Criteria.where("corporationCode").is(StringUtils.defaultString(queryDto.getCorporationCode(), QfContextHolder.getContext().getCorporationCode()));

        if (StringUtils.isNotBlank(queryDto.getCityCode())) {
            criteria.and("cityCode").is(queryDto.getCityCode());
        } else if (!CollectionUtils.isEmpty(queryDto.getCityCodes())){
            criteria.and("cityCode").in(queryDto.getCityCodes());
        }

        if (queryDto.getBeginDate() != null || queryDto.getEndDate() != null) {
            if (queryDto.getBeginDate() == null) {
                criteria.and("msgTimestamp").lte(queryDto.getEndDate());
            } else if (queryDto.getEndDate() == null) {
                criteria.and("msgTimestamp").gte(queryDto.getBeginDate());
            } else {
                criteria.andOperator(
                        Criteria.where("msgTimestamp").gte(queryDto.getBeginDate()),
                        Criteria.where("msgTimestamp").lte(queryDto.getEndDate())
                );
            }
        }
        if (StringUtils.isNotEmpty(queryDto.getFuzzyQueryStr())) {
            criteria.orOperator(Criteria.where("memberName").regex(".*?" + queryDto.getFuzzyQueryStr() + ".*"),
                    Criteria.where("employeeName").regex(".*?" + queryDto.getFuzzyQueryStr() + ".*"),
                    Criteria.where("propertyInfo").regex(".*?" + queryDto.getFuzzyQueryStr() + ".*"));
        }
        query.addCriteria(criteria);
        query.with(Sort.by(
                Sort.Order.desc("updateTime")
        ));
        return query;
    }

    @Override
    public void opYxImMessage(String corporationCode) {
        //获取该集团所有未处理的微聊记录
        List<YxImMessage> yxImMessages = repository.findAllByCronOpFlagAndCorporationCode(false, corporationCode);
        if (CollectionUtils.isEmpty(yxImMessages)) {
            return;
        }
        //获取城市map
        Map<String, String> cityMap = cityCompanyService.getCityMap(corporationCode);
        for (YxImMessage yxImMessage : yxImMessages) {
            String businessType = yxImMessage.getBusinessType();
            String fromAccid = yxImMessage.getFromAccid();
            String toAccid = yxImMessage.getToAccid();
            JSONObject dataJson = JSONObject.parseObject(yxImMessage.getLastmsgtext());
            Date msgTimestamp = yxImMessage.getMsgTimestamp();
            String msgType = yxImMessage.getMsgType();
            String fromUser = yxImUserService.getYxImUserIdAndType(fromAccid);
            String toUser = yxImUserService.getYxImUserIdAndType(toAccid);
            if (StringUtils.isEmpty(fromUser) || StringUtils.isEmpty(toUser) || !fromUser.contains(":") || !toUser.contains(":")) {
                alterCronOpFlag(yxImMessage.getId());
                continue;
            }
            String[] splitFromUser = fromUser.split(":");
            String[] splitToUser = toUser.split(":");
            if (splitFromUser.length != 2 || splitToUser.length != 2) {
                alterCronOpFlag(yxImMessage.getId());
                continue;
            }
            String memberId = null;
            String employeeUniqueUuid = null;
            if (UserType.MINI_PROGRAM.getCode().equals(splitFromUser[1])) {
                memberId = splitFromUser[0];
                employeeUniqueUuid = splitToUser[0];
            } else {
                memberId = splitToUser[0];
                employeeUniqueUuid = splitFromUser[0];
            }
            String memberPhone = memberService.getMemberPhone(memberId);
            Employee employee = employeeService.findByEmployeeUniqueUuid(employeeUniqueUuid);
            String employeeName = employee.getEmployeeName();
            String cityCode = employee.getCityCode();
            String cityName = cityMap.get(cityCode);
            String deptUuid = employee.getDeptUuid();
            String deptName = employee.getDeptName();
            if (StringUtils.isEmpty(deptName)) {
                deptName = departmentService.getDeptName(corporationCode, employee.getCompanyUuid(), deptUuid);
            }

            //获取房源信息
            String propertyInfo = "";
            if ("100".equals(businessType) || "101".equals(businessType)) {
                propertyInfo = dataJson.getString("replyMsg");
            } else {
                switch (businessType) {
                    case "1":
                        propertyInfo = dataJson.getString("estateName") + "/" + dataJson.get("sellPrice") + dataJson.getString("sellPriceUnit");
                        break;
                    case "2":
                        propertyInfo = "二手房/" + dataJson.getString("estateName") + "/" + dataJson.getString("roomType") + "/" + dataJson.get("sellPrice") + dataJson.getString("sellPriceUnit") + "/" + dataJson.getString("propertyNo");
                        break;
                    case "3":
                        propertyInfo = "租房/" + dataJson.getString("estateName") + "/" + dataJson.getString("roomType") + "/" + dataJson.get("rentPrice") + dataJson.getString("rentPriceUnit") + "/" + dataJson.getString("propertyNo");
                        break;
                }
            }
            propertyInfo = propertyInfo.replaceAll("/null", "");

            MessageList messageList = messageListRepository.findByMemberIdAndEmployeeUniqueUuid(memberId, employeeUniqueUuid);
            if (messageList != null) {
                messageList.setDeptUuid(deptUuid);
                messageList.setDeptName(deptName);
                messageList.setCityName(cityName);
                messageList.setCityCode(cityCode);
                messageList.setMemberName(memberPhone);
                messageList.setEmployeeName(employeeName);
                messageList.setMsgTimestamp(msgTimestamp);
                if (!"100".equals(businessType) && !"101".equals(businessType)) {
                    messageList.setPropertyInfo(propertyInfo);
                }
                List<MessageParam> messageParamList = messageList.getMessageParamList();
                messageParamList.add(0, MessageParam.builder()
                        .messageFrom(UserType.MINI_PROGRAM.getCode().equals(splitFromUser[1]) ? memberPhone : employeeName)
                        .messageType(msgType)
                        .messageText(propertyInfo)
                        .msgTimestamp(msgTimestamp)
                        .build());
                messageList.setMessageParamList(messageParamList);
            } else {
                List<MessageParam> messageParamList = new LinkedList<>();
                messageParamList.add(0, MessageParam.builder()
                        .messageFrom(UserType.MINI_PROGRAM.getCode().equals(splitFromUser[1]) ? memberPhone : employeeName)
                        .messageType(msgType)
                        .messageText(propertyInfo)
                        .msgTimestamp(msgTimestamp)
                        .build());
                messageList = MessageList.builder()
                        .memberId(memberId)
                        .employeeUniqueUuid(employeeUniqueUuid)
                        .memberName(memberPhone)
                        .employeeName(employeeName)
                        .deptUuid(deptUuid)
                        .deptName(deptName)
                        .cityName(cityName)
                        .msgTimestamp(msgTimestamp)
                        .messageParamList(messageParamList)
                        .build();
                if (!"100".equals(businessType) && !"101".equals(businessType)) {
                    messageList.setPropertyInfo(propertyInfo);
                }
                messageList.setCorporationCode(corporationCode);
                messageList.setCityCode(cityCode);
            }
            messageListRepository.save(messageList);
            //处理完之后更改源数据状态
            alterCronOpFlag(yxImMessage.getId());
        }
    }

    private void alterCronOpFlag(String id) {
        YxImMessage yxImMessage = new YxImMessage();
        yxImMessage.setId(id);
        yxImMessage.setCronOpFlag(true);
        updateById(yxImMessage);
    }

    /**
     * 根据fromAccount获取集团code
     *
     * @param fromAccount
     * @return
     */
    private String getCorporationCodeByAccid(String fromAccount) {
        String prefix = fromAccount.substring(0, fromAccount.lastIndexOf("-") + 1);
        Query query = new Query();
        query.addCriteria(Criteria.where("accidPrefix").is(prefix));
        List<Corporation> corporation = mongoTemplate.find(query, Corporation.class);
        if (CollectionUtils.isEmpty(corporation)) {
            return null;
        }
        return corporation.get(0).getCorporationCode();
    }
}
